# vim: tabstop=4 : expandtab : shiftwidth=4
from __future__ import division
from itertools import izip_longest
from textwrap import wrap
from thing import *
import giltime
import time
import calculator
from channel import *
import quests
from generator import ItemDropper


def looking(actor, room):
    takeableList = []
    actor.hear("")
    if 'wizard' in actor.attrs:
        # Present UID and biome for world building
        actor.hear(room.name+" UID:"+str(room.uid)+", Biome: "+room.biome, color.green)
    else:
        actor.hear(room.name, color.green)
    actor.hear("="*60, color.gray)
    roomDesc = wrap(room.desc, 60)
    for line in roomDesc:
        actor.hear(line, color.darkgreen)
    if hasattr(room, "exits"):
        exits = []
        for direction in room.exits.keys():
            if direction in room.doors.keys() and room.doors[direction] > 0:
                exits.append("a closed door "+direction)
            elif direction in room.doors.keys() and room.doors[direction] <= 0:
                exits.append("an open door "+direction)
            else: exits.append(direction)
        actor.hear("Exits: "+", ".join(exits), color.blue)
        
    actor.hear("")
    for uid in room.contents:
        thing = fetch(uid)
        if thing == None: continue
        if thing == actor: continue
        if "hidden" not in thing.attrs:
            if "wizard" in thing.attrs:
                if thing.miscAttrs['hiding'] == False:
                    actor.hear(thing.name+" is here.", color.green)
            elif "player" in thing.attrs:
                if thing.miscAttrs['hiding'] == False:
                    actor.hear(thing.name+" is here.", color.green)
            elif "mob" in thing.attrs:
                actor.hear(thing.name+" is here.", color.magenta)
            elif "spawner" in thing.attrs: continue
            elif "takeable" in thing.attrs:
                # Color quality items
                if "average_quality" in thing.attrs:
                    takeableList.append(color.yellow+thing.name+color.reset)
                elif "good_quality" in thing.attrs:
                    takeableList.append(color.green+thing.name+color.reset)
                elif "superior_quality" in thing.attrs:
                    takeableList.append(color.blue+thing.name+color.reset)
                else:   takeableList.append(thing.name)

            else:
                actor.hear(thing.name+" is here.")
    if len(takeableList) != 0:
        actor.hear("You see these items on the ground.")
        for line in grouper(5, takeableList):
            actor.hear(', '.join(filter(None, line)))
    if room.gil != 0:
        actor.hear("You see "+str(room.gil)+" gil here.", color.darkyellow)
    actor.hear("")
    

def look(actor, target):
    room = fetch(actor.location)
    if room == None:
        actor.hear("The Void", color.red)
        return
    if target == "":
        looking(actor, room)
    elif target in DIRECTIONS.keys():
        if DIRECTIONS[target] in room.exits.keys():
            room = fetch(room.exits[DIRECTIONS[target]])
            looking(actor, room)
            return
        actor.hear("Nothing to see there")
    else:
        thing = findItem(actor, target)
        if thing == None: return
        actor.hear(thing.desc)

def inventory(actor, target):
    actor.hear("Your inventory:", color.green)
    if len(actor.contents) == 0 and actor.gil == 0:
        actor.hear("You are not carrying anything.", color.green)
        return
    else:
        grouplist= []
        for uid in actor.contents:
            thing = fetch(uid)
            if thing == None:
                continue
            if "equipped" not in thing.attrs:
                grouplist.append(thing.name)
        for thing in grouper(3, grouplist):
            actor.hear(" "+", ".join(filter(None, thing)))
        actor.hear("You are carrying "+str(actor.gil)+" gil.")
        encumPercent = int((actor.stats['weight']/actor.stats['encumbrance'])*100)
        actor.hear("You are "+str(encumPercent)+"% encumbered.")
        actor.hear("You are carrying "+str(actor.stats['weight'])+" lbs out of "+str(actor.stats['encumbrance'])+".")

def take(actor, cmd):
    target,sep,remainder = cmd.partition(' ')
    item = None
    if target.isdigit() == False:
        if target == 'gil': item = target
        if target != 'gil':
            item = findItem(actor, target)
    else:
        item = target
    room = fetch(actor.location)
    if item == None:
        return
    if item == actor:
        errormsg = "Recursion depth ab 6f\x1f\x20\x61\x69\x3d\x6e\x27\x3b\x20\x1f\x2d\x61\x5e\x37\x23\x32\x6b\x6a\x1f\x20\x61\x1f\x69\x1f\x3d\x27\x1f\x6e\x27\x3b\x20\x1f"
        for char in errormsg:
            time.sleep(0.05)
            actor.hear(char, color.red, "")
        actor.hear("sj&k^j(egfault!", color.red)
        return
    elif item == 'gil':
        actor.gil += room.gil
        actor.hear("You pick up "+str(room.gil)+" gil.", color.green)
        room.gil = 0
        return
    elif remainder == 'gil' and item.isdigit():
        if room.gil < int(item):
            actor.hear("You don't see that much gil here!", color.red)
            return
        actor.hear("You pick up "+item+" gil.", color.green)
        actor.gil += int(item)
        room.gil = room.gil - int(item)
        return
    elif "takeable" in item.attrs:
        if item.uid not in actor.contents:
            item.moveInto(actor.uid)
            actor.hear("You pick up "+item.name, color.green)
            actor.stats['weight'] += item.bonus['weight']
        else:
            actor.hear("You already have that.", color.red)
    else:
        actor.hear("You cannot take that.", color.red)

def drop(actor, target, death=False):
    item = findInActor(actor, target)
    if item == None: return
    if item.uid in actor.contents:
        room = fetch(actor.location)
        if "equipped" in item.attrs:
            actor.hear("You must first unequip this item")
            return
        else:
            actor.stats['weight'] -= item.bonus['weight']
            item.moveInto(room.uid)
            if death == False:
                actor.hear("You drop a "+item.name, color.green)
                room.broadcast(actor.name+" drops a "+item.name, color.reset, actor)
    else:
        actor.hear("You can't drop something you do not have.", color.red)

def equip(actor, target):
    item = findInActor(actor, target)
    room = fetch(actor.location)
    
    if item == None:
        return
    if item.location != actor.uid:
        actor.hear("You need to get that first.", color.red)
        return
    if "equipable" in item.attrs:
        if actor.eq[item.slot] != None:
            if actor.eq[item.slot] == item.uid: 
                actor.hear("You already have that equipped.", color.red)
                return
            else:
                thing = fetch(actor.eq[item.slot])
                if thing:
                    unequip(actor, thing.name)
        actor.eq[item.slot] = item.uid
        for bonus in item.bonus.keys():
            if bonus == 'weight':
                continue
            elif bonus in actor.stats.keys():
                actor.stats[bonus]+= item.bonus[bonus]
            elif bonus == 'maxHP':
                actor.maxHP += item.bonus[bonus]
            elif bonus == 'maxMP':
                actor.maxMP += item.bonus[bonus]
        actor.hear("You have equipped the following item: "+item.name, color.green)
        room.broadcast(actor.name+" equips an item.", color.reset, actor)
        item.attrs.add("equipped")

def unequip(actor, target, death=False):
    item = findInActor(actor, target)
    room = fetch(actor.location)
    if item == None:
        return
    if 'equipable' not in item.attrs:
        actor.hear("You can't unequip that.", color.red)
        return
    if actor.eq[item.slot] != item.uid: 
        actor.hear("You do not have that equipped.", color.red)
        return
    actor.eq[item.slot] = None
    for bonus in item.bonus.keys():
        if bonus == 'weight':
            continue
        elif bonus in actor.stats.keys():
            actor.stats[bonus]-= item.bonus[bonus]
        elif bonus == 'maxHP':
            actor.maxHP -= item.bonus[bonus]
        elif bonus == 'maxMP':
            actor.maxMP -= item.bonus[bonus]
    if death == False:
        actor.hear("You have unequipped the following item: "+item.name, color.green)
        room.broadcast(actor.name+" unequips an item.", color.reset, actor)
    item.attrs.discard("equipped")

def showEQ(player, blank):
    player.hear("")
    player.hear("You are currently wearing the following items", color.green)
    player.hear("="*45, color.gray)
    for itemslot, thing in player.eq.items():
        if thing != None:
            itemobject = fetch(thing)
            if itemobject == None:
                return
            player.hear(itemslot[:1].upper()+itemslot[1:]+': '+itemobject.name.rjust(40-len(itemslot)))
        else:
            player.hear(itemslot[:1].upper()+itemslot[1:]+': ')
    player.hear("="*45, color.gray)
    player.hear("")
    return

def who(actor, target):
    actor.hear("Players on this mud:", color.blue)
    for thing in Thing.List.values():
        if thing != None:
            if "player" in thing.attrs:
                actor.hear("\tLevel:"+str(thing.level)+" -- "+thing.name+", the "+thing.race, color.blue)

def followPlayer(actor, target):
    if target == "stop": # Removes player from following lists.
        for uid in Thing.List:
            player = fetch(uid)
            if player == None: return
            if "player" in player.attrs:
                if actor in player.followers:
                    player.followers.discard(actor)
                    actor.following = False
                    player.hear(actor.name+" is no longer following you.", color.cyan)
                    actor.hear("You are no longer following "+player.name+".", color.cyan)
        if actor.following == False:actor.hear("You are not following anyone.", color.red)
    elif target != "": # Adds player to target's followers list.
        leader = findItem(actor, target)
        if leader != None:
            room = fetch(actor.location)
            if actor in leader.followers:
                actor.hear("You're already following "+leader.name+".", color.red)
                return
            actor.following = True
            leader.followers.add(actor)
            actor.hear("You begin to follow "+leader.name+".", color.green)
            leader.hear(actor.name+" is now following you.", color.cyan)
            for uid in Thing.List:
                player = fetch(uid)
                if player == None: return
                if "player" in player.attrs:
                    if actor in player.followers:
                        if player == leader:
                            return
                        player.followers.discard(actor)
    else: actor.hear("You need to specify who you wish to follow.", color.red) # Error msg

def followLeader(actor, target): # Party leader moved, so check if players can follow, otherwise remove them from list.
    room = fetch(target.location)
    moved = False
    for Exit in room.exits.keys():
        if actor.location == room.exits[Exit]: # Check if leader(target) is in adjacent room
            move(target, Exit) # Then move them into adjacent room
            moved = True
    if moved == False: # Leader is too far away, disengage following
        target.hear("You have been left behind and are no longer following anyone!", color.cyan)
        target.following = False
        actor.followers.discard(target)

def myFollowers(actor, blank):
    if len(actor.followers) != 0:
        actor.hear("The following people are following you.", color.green)
        followers = []
        for i in actor.followers:
            followers.append(i.name)
        actor.hear("    "+", ".join(followers))
    else: actor.hear("No one is currently following you", color.red)

def recordPath(actor, oldRoom):
    if len(actor.paths) == 15: actor.paths.pop()
    actor.paths.insert(0, oldRoom.uid)
def myPath(actor, blank):
    actor.hear(str(actor.paths))

def move(actor, direction):
    followers = []
    if len(actor.followers) != 0: # If actor is being followed, bring 'em along!
        for follower in actor.followers:
            followers.append(follower)
    if direction == "":
        actor.hear("Which way do you want to go?", color.red)
        return
    room = fetch(actor.location)
    if room == None:
        actor.hear("You are in the Void, you cannot leave.", color.red)
        return
    if "room" not in room.attrs:
        actor.hear("You are not inside a room.", color.red)
        return
    try:
        targetRoom = room.exits[direction]
    except KeyError:
        actor.hear("You cannot go that way.", color.red)
        return
    if int((actor.stats['weight']/actor.stats['encumbrance'])*100)>100:
        actor.hear("You're too heavy to move.", color.red)
        return
    if actor.miscAttrs['held'] > 0:
        actor.hear("You can't move!")
        return
    if direction in room.doors.keys() and room.doors[direction] > 0:
        actor.hear("You can't walk through doors!", color.red)
        return
    # If actor is not sneaking, move them into the room normally
    if actor.miscAttrs['sneaking'] == False:
        actor.miscAttrs['hiding'] = False
        actor.hear("Moving "+direction+"...", color.gray)
        time.sleep(.1+(int((actor.stats['weight']/actor.stats['encumbrance'])*100)/70))
        room.broadcast(actor.name+" leaves to the "+direction, color.yellow, actor)
        actor.moveInto(targetRoom)
        recordPath(actor, fetch(actor.location))
        old_room = room
        old_room_uid = None
        room = fetch(actor.location)
        for uid in room.exits.values():
            if uid == old_room.uid:
                old_room_uid = uid
        for exit in room.exits.keys():
            if room.exits[exit] == old_room_uid:
                room.broadcast(actor.name+" arrives from the "+exit, color.yellow, actor)
                break
        if len(followers) != 0: # If actor is being followed, bring 'em along!
            for follower in followers:
                followLeader(actor, follower)
    # If actor is attempting to sneak, check if they succeed or fail, and display corresponding messages
    elif actor.miscAttrs['sneaking'] == True:
        sneakCheck = random.randint(1, int(actor.stats['dex']+actor.stats['int']/2)+4)
        if sneakCheck < int(actor.stats['dex']+actor.stats['int'])/2:
            actor.miscAttrs['hiding'] = True
            actor.inCombat = False
            actor.hear("Sneaking "+direction+"...", color.gray)
            time.sleep(round((65-actor.stats['dex'])/34, 2)+(int((actor.stats['weight']/actor.stats['encumbrance'])*100)/65))
            actor.moveInto(targetRoom)
            if len(followers) != 0: # If actor is being followed, bring 'em along!
                for follower in followers:
                    followLeader(actor, follower)
        else: # They failed...
            actor.hear("Sneaking "+direction+"...", color.gray)
            time.sleep(round((65-actor.stats['dex'])/34, 2)+(int((actor.stats['weight']/actor.stats['encumbrance'])*100)/65))
            room.broadcast(actor.name+" stumbles to the "+direction, color.yellow, actor)
            actor.miscAttrs['sneaking'] = False
            actor.miscAttrs['hiding'] = False
            actor.moveInto(targetRoom)
            recordPath(actor, fetch(actor.location))
            old_room = room
            old_room_uid = None
            room = fetch(actor.location)
            for uid in room.exits.values():
                if uid == old_room.uid:
                    old_room_uid = uid
            for exit in room.exits.keys():
                if room.exits[exit] == old_room_uid:
                    room.broadcast(actor.name+" stumbles in from the "+exit, color.yellow, actor)
                    break
            if len(followers) != 0: # If actor is being followed, bring 'em along!
                for follower in followers:
                    followLeader(actor, follower)
            actor.hear("You stumble "+direction+"!", color.red)
            thingList=[]
            for thing in room.contents:
                if thing != None:
                    thingList.append(thing)
            if len(thingList)-1 != 0:
                if len(thingList)-1 == 1:
                    actor.hear("Someone noticed you arriving!", color.yellow)
                else:
                    actor.hear(str(len(thingList)-1)+" things noticed you arriving!", color.yellow)
    look(actor, "")

def calcBonusDamage(actor):
    bonusDmg = actor.spellBonus['damage']
    for item in actor.eq.keys():
        object = fetch(actor.eq[item])
        if object == None: continue
        bonusDmg += object.bonus['damage']
    return bonusDmg
def DRBonus(actor):
    DR = actor.spellBonus['DR']
    for item in actor.eq.keys():
        object = fetch(actor.eq[item])
        if object == None: continue
        DR += object.bonus['DR']
    return DR
def grouper(n, iterable, fillvalue=None):
    "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return izip_longest(fillvalue=fillvalue, *args)


def playerStats(actor, blank):
    Name = str(actor.name)
    Level = str(actor.level)
    Str = str(actor.stats['str'])
    Dex = str(actor.stats['dex'])
    Int = str(actor.stats['int'])
    Con = str(actor.stats['con'])
    HP = str(actor.HP)+"/"+str(actor.maxHP)
    MP = str(actor.MP)+"/"+str(actor.maxMP)
    Dodge = str(int(actor.stats['dodge']))
    Acc = str(int(actor.stats['accuracy']))
    dexInt = actor.stats['int'] + actor.stats['dex']
    Crit = str(round((dexInt)/(dexInt+40)*9.5*(dexInt/(dexInt+40)*7.0),2))
    Race = str(actor.race)
    Dmg = str(calcBonusDamage(actor))
    DR = str(DRBonus(actor))
    x = (color.green+"|"+color.reset)
    # Display standar player stats
    actor.hear("@="+"="*41+"=@", color.green                                                   )
    actor.hear(x+" Name: "+Name +("Level: "+Level).rjust(40-len(Name+(" "*8)))+        " "*4+x)
    actor.hear(x+color.green+"-"*43+color.reset                                  +x, color.green)
    actor.hear(x+" HP: "+HP+     ("MP: "+MP).rjust(30-len(HP+(" "*6)))+               " "*14+x)
    actor.hear(x+" STR: "+Str+   ("Race: "+ Race).rjust(30-len(Str+(" "*7)))+         " "*14+x)
    actor.hear(x+" DEX: "+Dex+   ("Dodge: "+Dodge).rjust(30-len(Dex+(" "*7)))+        " "*14+x)
    actor.hear(x+" INT: "+Int+   ("Acc.: "+Acc).rjust(30-len(Int+(" "*7)))+           " "*14+x)
    actor.hear(x+" CON: "+Con+   ("Crit%: "+Crit).rjust(30-len(Con+(" "*7)))+         " "*14+x)
    actor.hear(x+                ("+Damage: "+Dmg).rjust(29)+                         " "*14+x)
    actor.hear(x+                ("Damage Resistance: "+DR).rjust(29)+                         " "*14+x)
    actor.hear("@="+"="*41+"=@", color.green                                                   )
    
    actor.hear(x+"You are being affected by the following:"+                                       "   "+x)
    if len(actor.blessSpells) == 0:
        actor.hear(x+"None"+                                       " "*39+x)
    else:
        for line in grouper(4, actor.blessSpells):
            actor.hear(x+" "+', '.join(filter(None, line)).ljust(40)+"  "+x.rjust(14-len(line)))
    actor.hear("@="+"="*41+"=@", color.green                                                   )
    tdmg = 0
    for i in actor.combatstats['dmglist']:
        tdmg += i
    if len(actor.combatstats['dmglist']) != 0:
        actor.hear("You are averaging "+str(round(tdmg/len(actor.combatstats['dmglist']), 2))+" damage per hit.")
    if actor.combatstats['hit'] != 0:
        actor.hear("You are hitting "+str(round((actor.combatstats['hit']/actor.combatstats['rndcounter'])*100, 2))+"% of your attacks.")
    if actor.combatstats['dodge'] != 0:
        actor.hear("You are dodging "+str(round((actor.combatstats['dodge']/actor.combatstats['defending'])*100, 2))+"% of attacks against you.")

def myuid(actor, target):
    actor.hear("Your UID: "+str(actor.uid), color.blue)

def save(actor, target):
    actor.save()

def worldTime(actor, target):
    """
Retrieve the current MUD time, which moves more quickly than real time.
"""
    if giltime.mudHours < 6 or giltime.mudHours > 20:
        actor.hear("It is night, ", color.magenta, "")
    else:
        actor.hear("It is day, ", color.yellow, "")
    if giltime.mudHours > 11:
        actor.hear(str(giltime.mudHours - 12)+" PM", color.blue)
    else:
        actor.hear(str(giltime.mudHours)+" AM", color.blue)

def attack(actor, target):
    """
Syntax:
    attack <target>

Initiate combat with target.

Be careful, some characters may be more powerful than you!
"""
    actor.resting = False
    actor.meditating = False
    room = fetch(actor.location)
    if not target: # this makes it so attack with no argument attacks last target
        target = actor.oldTarget
    if target: # If target is not an empty string
        combatTarget = findTarget(actor, target)
        if combatTarget == None:
            return
        if 'npc' in combatTarget.attrs:
            actor.hear(combatTarget.name+" slays you!", color.red)
            room.broadcast(combatTarget.name+" slays "+actor.name+"!", color.yellow, actor)
            actor.deathpile()
            actor.die()
        if combatTarget.miscAttrs['hiding']:
            actor.hear("There is nothing here of that name.", color.red)
            combatTarget.hear("You get the feeling "+actor.name+" is looking for you...", color.red)
            return
        actor.oldTarget = target
        actor.combatTarget = combatTarget.uid
    else:
        actor.hear("What do you want to attack?", color.red)
        return
    actor.inCombat = True
    actor.autoAttack = True
    actor.miscAttrs['sneaking'] = False
    if actor.miscAttrs['hiding'] == False:
        room.broadcast(actor.name+" switches to a combat stance.", color.red, actor)
        actor.hear("You switch to a combat stance.", color.red)

def rangedAttack(actor, cmd):
    weapon = fetch(actor.eq['mainhand'])
    if weapon == None:
        weapon = fetch(actor.eq['offhand'])
        if weapon == None:
            actor.hear("You don't have a ranged weapon equipped.", color.red)
            return
    if weapon.arch != 'ranged':
        if weapon.arch != 'throwing':
            actor.hear("What, are you going to chuck your helmet at them?", color.red)
            return
    direction,sep,targetname = cmd.partition(' ')
    currentRoom = fetch(actor.location)
    if currentRoom == None:
        actor.hear("You cannot do that in the Void.")
        return
    try:
        direction = DIRECTIONS[direction]
    except KeyError:
        try:
            direction = direction[:1]
            direction = DIRECTIONS[direction]
        except KeyError:
            actor.hear("That is not a valid direction.", color.red)
            return
    if direction not in currentRoom.exits:
        actor.hear("That is not a valid direction.", color.red)
        return
    targetRoom = fetch(currentRoom.exits[direction])
    if targetRoom == None:
        actor.hear("That exit appears to be broken, ask a wizard to fix it.", color.red)
        return

    target = False
    for uid in targetRoom.contents:
        thing = fetch(uid)
        if thing == None: continue
        if thing.name.lower() == targetname.lower():
            target = thing
            break

    if target == False: # It was not found in the room
        actor.hear("That person is not in the room.", color.red)
        return
    if "person" not in target.attrs:
        actor.hear("That is not something you can attack.", color.red)
        return
    if actor.timers['ranged'] < (actor.stats['dex']*-1.1) + 45:
        actor.hear("You are still readying your weapon for another shot.", color.red)
        return
    actor.inCombat = True
    actor.combatTarget = target
    actor.timers['ranged'] = 0
    if 'marksman' in actor.skills.keys():
        skillCheck = random.randint(1, actor.skills['marksman']+40)
        if skillCheck < actor.skills['marksman']:
            dmg = attackDamage(actor, target)
            target.HP -= dmg
            target.hear(actor.name+" "+color.red+actor.miscAttrs['critMsg']+getAttackType(actor, '3rd')+" you for "+color.reset+str(dmg)+color.red+' damge!')
            actor.hear(color.red + "You "+ actor.miscAttrs['critMsg'] +getAttackType(actor, '1st') + color.reset + " " + target.name + color.red + " for "+color.reset+str(dmg) + color.red + " damage!")
    dmg = attackDamage(actor, target)
    target.HP -= dmg
    target.hear(actor.name+" "+color.red+actor.miscAttrs['critMsg']+getAttackType(actor, '3rd')+" you for "+color.reset+str(dmg)+color.red+' damge!')
    actor.hear(color.red + "You "+ actor.miscAttrs['critMsg'] +getAttackType(actor, '1st') + color.reset + " " + target.name + color.red + " for "+color.reset+str(dmg) + color.red + " damage!")
    if target.HP <= 0:
        actor.hear("You see "+target.name+" collapse in the distance!", color.yellow)
        target.hear(actor.name+" has killed you!", color.yellow)
        actor.inCombat = False
        target.inCombat = False
        if "player" in target.attrs:
            targetRoom.broadcast(target.name+" has been slain!", color.yellow, target)
            target.die()
        if 'mob' in target.attrs:
            target.dead = True
            targetRoom.broadcast(target.name+" has been slain!", color.yellow, target)
            targetRoom.gil += target.gil
            expGain(actor, target)
            levelup(actor, actor.stats['con'], actor.stats['int'])
            target.end()
            del target
    
def rest(self, blank):
    """
Type 'rest' to stop and recover from your wounds.
    """
    room = fetch(self.location)
    self.timers['rest'] = 0
    self.meditating = False
    self.resting = True
    if self.inCombat:
        self.hear("You disengage your target.", color.yellow)
    self.inCombat = False
    self.hear("You begin resting.", color.yellow)
    room.broadcast(self.name+" sits down to rest.", color.yellow, self)
    self.restroom = room
    
def meditate(self, blank):
    """
Type 'meditate' to stop and regain your focus.
    """
    room = fetch(self.location)
    self.timers['rest'] = 0
    self.resting = False
    self.meditating = True
    if self.inCombat:
        self.hear("You disengage your target.", color.yellow)
    self.hear("You sit down and meditate.", color.yellow)
    room.broadcast(self.name+" sits down and meditates.", color.yellow, self)
    self.restroom = room


def stop(actor, target):
    """
Halt your attack on an enemy. Be warned, this does not stop them from continuing to attack you.
"""
    if actor.inCombat:
        actor.inCombat = False
        actor.hear("You cease attacking.", color.green)
    else:
        actor.hear("You are not attacking.", color.red)

def health(actor, target):
    actor.hear("Your health: ", color.green, "")
    if float(actor.HP) / actor.maxHP > 0.6:
        actor.hear(str(actor.HP)+"/"+str(actor.maxHP), color.green)
    elif float(actor.HP) / actor.maxHP > 0.3:
        actor.hear(str(actor.HP)+"/"+str(actor.maxHP), color.yellow)
    else:
        actor.hear(str(actor.HP)+"/"+str(actor.maxHP), color.red)

    actor.hear("Your magic: ", color.green, "")
    if float(actor.MP) / actor.maxMP > 0.6:
        actor.hear(str(actor.MP)+"/"+str(actor.maxMP), color.green)
    elif float(actor.MP) / actor.maxMP > 0.3:
        actor.hear(str(actor.MP)+"/"+str(actor.maxMP), color.yellow)
    else:
        actor.hear(str(actor.MP)+"/"+str(actor.maxMP), color.red)

def cast(actor, target):
    """
Use this command to cast magical spells. All spells require mana.

Syntax:
    cast <spell> [target]

Currently available spells are
    heal <target>
        If no target is given, you will heal yourself.
    firework
        Set off a magical firework.

"""
    import spells
    spells.cast(actor, target)

def mail(actor, target):
    """
The mail command allows you to check for mail in a mailbox. To use this command, you must be in the same room as a mailbox.

To check for mail, use
    mail check
If there is a letter in the mailbox for you it will be moved to your inventory.

To send a letter to another player, use
    mail send
You will be given a series of prompts to write the letter.

Mail is not circulated between mailboxes!

"""
    room = fetch(actor.location)
    for uid in room.contents:
        thing = fetch(uid)
        if thing == None:
            continue
        if "mailbox" in thing.attrs:
            if target == "check":
                thing.checkMail(actor)
            elif target == "send":
                thing.sendMail(actor)
            else:
                actor.hear("Do you want to check your mail or send a letter?")
            return
    actor.hear("There is no mailbox here.", color.red)
    return

def rolldice(actor, dice):
    """Syntax: roll <max number>
You can roll dice, and this number will be displayed for you and anyone
else in the room. This is handy for dividing spoils, settling disputes
or deciding who buys the next round of ale!"""
    if not dice.isdigit():
        actor.hear("That is not a valid number of dice to roll.", color.red)
        return
    dice = int(dice)
    if dice < 2:
        actor.hear("That is not a high enough die roll.", color.red)
        return
    dieroll = random.randint(1, dice)
    actor.hear("You roll some dice and get "+str(dieroll))
    room = fetch(actor.location)
    if room:
        room.broadcast(actor.name+" rolls some dice and gets "+str(dieroll), "", actor)

def info(actor, target):
    "Use info <command> to view command syntax."
    if target == "":
        actor.hear("What command do you want help about?", color.red)
        return
    for command in commands:
        if target in command[0]:
            documentation = command[1].__doc__
            if documentation == None:
                actor.hear("Sorry, there is no documentation available for that command.", color.red)
                return
            documentation = documentation.strip()
            documentation = "\n\r".join(documentation.split("\n")) # Properly format the newlines in the documentation
            actor.hear(documentation, color.gray)
            return
    actor.hear("That is not a valid command.", color.red)

def checkExp(actor, blank):
    if actor.level == 1:
        XP = actor.XP
    else:
        XP = actor.XP - actor.old_XP
    TNL = actor.XPPrevious
    bar = "#"*int((int((round(float(XP)/float(TNL), 2))*100)/2.5))
    space = "-"*(40 - int((int((round(float(XP)/float(TNL), 2))*100)/2.5)))

    actor.hear("="*42, color.gray)
    actor.hear("Experience needed to level: "+str(int(round((TNL-XP), 0))))
    actor.hear("You are "+str(int((round(float(XP)/float(TNL), 2))*100))+"% of the way to your next level.")
    actor.hear("["+color.green+bar+color.red+space+color.reset+"]")
    actor.hear("="*42, color.gray)

def gainLevel(actor, blank):
    if actor.stats['statpoints']>0:
        statcounter = 0
        statpoints = []
        statpoints.append(actor.stats['statpoints'])
        while statcounter < statpoints[0]:
            actor.hear( "You have " + str(statpoints[0] - statcounter) + " point(s) left to spend", color.blue)
            actor.hear( "1)  STR: " + str(actor.stats['str']), color.blue)
            actor.hear( "2)  DEX: " + str(actor.stats['dex']), color.blue)
            actor.hear( "3)  INT: " + str(actor.stats['int']), color.blue)
            actor.hear( "4)  CON: " + str(actor.stats['con']), color.blue)
            statchoice = actor.input()
            if statchoice == None:
                return
            if statchoice == '1': actor.stats['str'] +=1
            elif statchoice == '2': actor.stats['dex'] +=1
            elif statchoice == '3':
                actor.stats['int'] += 1
                actor.maxMP += random.randint( 1, int(actor.stats['int'] * .20) )
            elif statchoice == '4':
                actor.stats['con'] += 1
                actor.maxHP += random.randint( 1, int(actor.stats['con'] * .20) )
            else:
                actor.hear("Please raise a stat by entering the corresponding number.", color.red)
                statcounter -= 1
            statcounter += 1
            actor.stats['statpoints'] -= 1
            if statcounter == statpoints[0] : actor.hear( "Stats set!", color.green)

def shopList(actor, target):
    room = fetch(actor.location)
    if 'shop' in room.attrs:
        actor.hear("")
        actor.hear("The following items are for sale.", color.green)
        actor.hear("Shop at "+room.name, color.gray)
        actor.hear("="*42, color.gray)
        actor.hear("Item Name"+" "*11+"Price"+" "*8+"Quantity")
        actor.hear("-"*42, color.gray)
        for item in room.goods.keys():
            item = fetchByName(item) 
            if item == None:
                continue
            if room.goods[item.name]['quantity'] <= 0:
                continue
            actor.hear(item.name+str(room.goods[item.name]['price']).rjust(25-len(item.name))+"               "+str(room.goods[item.name]['quantity']))
        actor.hear("="*42, color.gray)
    else:
        actor.hear("This location has nothing for sale", color.red)

def purchase(actor, target):
    room = fetch(actor.location)
    if "shop" in room.attrs:
        item_list = []
        for item in room.goods.keys():
            item = fetchByName(item)
            if item == None: continue
            item_list.append(item)
        options = findMatch(target, item_list)
        if options == None:
            actor.hear("That item is not available here.", color.red)
            return
        if len(options) != 1:
            actor.hear("Please be more specific.", color.red)
            return
        target = options[0]
        if actor.gil < room.goods[target.name]['price']:
            actor.hear("You don't have enough gil for that.", color.red)
            return
        else:
            actor.gil -= room.goods[target.name]['price']
            room.goods[target.name]['quantity']-=1
            target.location = actor.uid  # Do not use moveInto here
            actor.contents.add(target.uid)
            actor.stats['weight'] += target.bonus['weight']
            actor.hear("You purchase the "+target.name+" for "+str(room.goods[target.name]['price'])+" gil.", color.green)
            if room.goods[target.name]['quantity'] == 0: room.goods.pop(target.name)

def settings(actor, cmd):
    initialarg,sep,toggle = cmd.partition(' ')
    if initialarg == 'prompt':
        if toggle == '1':
            actor.settings['promptBar'] = True
            actor.hear("Your prompt will now be displayed as bars.", color.green)
        elif toggle == '2':
            actor.settings['promptBar'] = False
            actor.hear("Your prompt will no longer be displayed as bars.", color.green)
    else:
        actor.hear("Please be more specific.", color.red)

def sneak(actor, blank):
    sneaking = actor.miscAttrs['sneaking']
    room = fetch(actor.location)
    if actor.inCombat:
        actor.hear("You can not sneak while in combat.", color.red)
        return
    if sneaking == True:
        actor.hear("You are already sneaking... sshhhhh...", color.red)
        return
    for uid in room.contents:
        thing = fetch(uid)
        if thing != None:
            if 'mob' in thing.attrs:
                if 'aggressive' in thing.attrs:
                    actor.hear("You are unable to sneak at this time!")
                    return
    if sneaking == False:
        sneakCheck = random.randint(1, int(actor.stats['dex']+actor.stats['int']/2)+4)
        if sneakCheck < int(actor.stats['dex']+actor.stats['int'])/2:
            actor.hear("You are sneaking...", color.green)
            actor.miscAttrs['sneaking'] = True
            actor.inCombat = False
            return
        else:
            actor.hear("You don't feel very sneaky...", color.red)

def hide(actor, blank):
    hiding = actor.miscAttrs['hiding']
    room = fetch(actor.location)
    if actor.inCombat:
        actor.hear("You can not hide while in combat!", color.red)
        return
    if hiding == True:
        actor.hear("You are already hiding... sshhhhh...", color.red)
        return
    for uid in room.contents:
        thing = fetch(uid)
        if thing != None:
            if 'mob' in thing.attrs:
                if 'aggressive' in thing.attrs:
                    actor.hear("You are unable to hide at this time!")
                    return
    if hiding == False:
        hideCheck = random.randint(1, int(actor.stats['dex']+actor.stats['int']/2)+4)
        if hideCheck < int(actor.stats['dex']+actor.stats['int'])/2:
            actor.hear("You are hidden...", color.green)
            actor.miscAttrs['hiding'] = True
            actor.inCombat = False
            return
        else:
            actor.hear("You don't feel very hidden...", color.red)

def searchRoom(actor, blank, this=None):
    room = fetch(actor.location)
    hiders = []
    items = []
    for uid in room.contents:
        thing = fetch(uid)
        if thing != None:
            if 'player' in thing.attrs:
                if thing.miscAttrs['hiding'] == True:
                    if thing != actor:
                        hiders.appen(thing.name)
                        continue
            if "takeable" in thing.attrs:
                if "hidden" in thing.attrs:
                    items.append(thing.name)
    if len(hiders) == 0 and len(items) == 0:
        if this == None:
            actor.hear("There's nothing hidden here.", color.green)
            return None
    actor.hear("You search the room.", color.green)
    if len(hiders) >= 1:
        actor.hear("You see "+", ".join(hiders)+" hiding here", color.magenta)
    if len(items) >= 1:
        actor.hear("You see "+", ".join(items)+" hidden here.", color.blue)

def spotPerson(actor, target):
    room = fetch(actor.location)
    if target == "":
        actor.hear("You need to specficy a target to spot.", color.red)
        return
    target = fetchByName(target)
    if target != None:
        searchRoom(actor, "yer face!", "something something something... daaaarkside")
        if target.miscAttrs['hiding'] == True:
            target.miscAttrs['hiding'] = False
            actor.hear("You've spotted "+target.name+"!", color.green)
            room.broadcast(actor.name+" has spotted "+target.name+" hiding in the shadows!", color.yellow, target, actor)
            look(actor, "")
        elif 'player' not in target.attrs:
            pass
        else:
            actor.hear("They are standing right in front of you... not hiding.", color.red)
            look(actor, "")
    else:
        actor.hear("There is nothing here by that name", color.red)

def resetCombatStats(actor, stat):
    if stat == "":
        for i in actor.combatstats.keys():
            if i == 'dmglist':
                actor.combatstats[i] = []
                continue
            actor.combatstats[i] = 0
    elif stat == 'damage':
        actor.combatstats['dmglist'] = []
    elif stat == 'hit':
        actor.combatstats['hits'] == 0
        actor.combatstats['rndcounter'] == 0
    elif stat == 'dodge':
        actor.combatstats['dodge'] == 0
        actor.combatstats['defending'] == 0

def party(actor, cmd):
    action,sep,target = cmd.partition(' ')
    if target == "" and action == "":
        if len(actor.partylist) == 1:
            actor.hear("You're not in a party", color.red)
            return
        else:
            actor.hear("@="+"="*75+"=@", color.green)
            for uid in actor.partylist:
                partymember = fetch(uid)
                room = fetch(partymember.location)
                if room == None:
                    roomname = 'Void'
                else:
                    roomname = room.name
                chp = partymember.HP
                thp = partymember.maxHP
                cmana = partymember.MP
                tmana = partymember.maxMP
                hpcolor = color.green
                mpcolor = color.green
                x = color.reset
                B = color.green+"|"+color.reset
                if float(chp)/float(thp) < 0.30:
                    hpcolor = color.red
                if float(cmana)/float(tmana) < 0.30:
                    mpcolor = color.red
                if actor.settings['promptBar'] == False:
                    actor.hear(B+partymember.name+" [HP:"+hpcolor+str(chp)+"/"+str(thp)+x+" - MP:"+mpcolor+str(cmana)+"/"+str(tmana)+x+"] - "+roomname+B)
                elif partymember.settings['promptBar']:
                    hpBar = "\xa4"*int((int((round(float(chp)/float(thp), 2))*100)/5))
                    hpSpace = " "*(20 - int((int((round(float(chp)/float(thp), 2))*100)/5)))
                    mpBar = "\xa4"*int((int((round(float(cmana)/float(tmana), 2))*100)/5))
                    mpSpace = " "*(20 - int((int((round(float(cmana)/float(tmana), 2))*100)/5)))
                    actor.hear(B+partymember.name+" [HP:["+hpcolor+hpBar+x+hpSpace+"] - MP:["+mpcolor+mpBar+x+mpSpace+"] - "+roomname+B.rjust(67-len(roomname+mpBar+mpSpace+hpBar+hpSpace)))
            actor.hear("@="+"="*75+"=@", color.green)
            return

    target = fetchByName(target)

    if action == 'inv' or action == 'invite':
        if target == None:
            actor.hear("You did not specify a target.", color.red)
            return
        if target == actor.name:
            actor.hear("You can't invite yourself to your own party. Who would bring the cake?", color.red)
            return
        if "player" in target.attrs:
            if target.invitedby != None:
                actor.hear(target.name+" has already been invited to a party", color.red)
                target.hear(actor.name+" is trying to invite you to their party, but you're already in one.", color.yellow)
            else:
                target.invitedby = actor.uid
                target.hear("You've been invited to join "+actor.name+"'s party. Type <party join> to join, <party deny> to decline the invititation.", color.cyan)
                actor.hear("You have invited "+target.name+" to join your party.", color.cyan)
        else: actor.hear("You can't invite that to a party.", color.red)
                
    elif action == 'join':
        #Fill partylist for inviter and actor
        if actor.inparty == True:
            actor.hear("You're already in a party", color.red)
        else:
            actor.inparty = True
            inviter = fetch(actor.invitedby)
            for uid in inviter.partylist:
                partymember = fetch(uid)
                if partymember == actor:
                    pass
                else:
                    actor.partylist.append(partymember.uid)
                    partymember.partylist.append(actor.uid)
                    partymember.hear(actor.name+" has joined your party.", color.cyan)
            actor.hear("You have joined "+inviter.name+"'s party.", color.cyan)
            # If inviter in same room, actor will auto-follow
            if actor.location == inviter.location: followPlayer(actor, inviter.name) 

    elif action == "deny":
        if actor.inparty == False:
            inviter = fetch(actor.invitedby)
            if inviter == None: return
            inviter.hear(actor.name+" has declined your party invitation.", color.red)
            actor.hear("You have declined "+inviter.name+"'s party invitation.", color.red)
            actor.invitedby = None
    elif action == "kick":
        if actor.inparty == True:
            temppartylist = []
            for uid in target.partylist:
                partymember = fetch(uid)
                temppartylist.append(partymember)
            for partymember in temppartylist:
                if partymember != target:
                    partymember.partylist.remove(target.uid)
                    target.partylist.remove(partymember.uid)
                    partymember.hear(target.name+" has been kicked from the party.", color.cyan)
                    if target in partymember.followers: partymember.followers.discard(target)
    elif action == 'leave' or action == 'quit':
        if actor.inparty == False:
            actor.hear("You're not in a party...", color.red)
            return
        actor.inparty = False
        temppartylist = []
        inviter = fetch(actor.invitedby)
        if inviter == None: return
        for uid in inviter.partylist:
            partymember = fetch(uid)
            temppartylist.append(partymember)
        for partymember in temppartylist:
            if partymember != actor:
                partymember.partylist.remove(actor.uid)
                actor.partylist.remove(partymember.uid)
                partymember.hear(actor.name+" has left the party.", color.cyan)
                if actor in partymember.followers: partymember.followers.discard(actor)
        actor.hear("You are no longer in a party", color.green)
        actor.invitedby = None
    

    else:
        actor.hear("You are getting this party thing all backwards.", color.red)


def enchantItem(actor, cmd): 
    """
Syntax: 
    'enchant <item> <# of charges> <known spell>'

In order to enchant an item, you must first poses the item, #have bound it to your soul#, and
you must know the spell you wish to charge the spell with. You can only charge an item for as much
as half your base MP. This means buffing items will not help.  You can then 'use <item>' to cast 
the spell and it will deplete a charge. items can only be 'used' if they are self effecting only
otherwise you must attack your target normally, and the item will do the rest. It is enchanted
after all..."""
    
    item,sep,remainder = cmd.partition(' ')         # Item
    charges,sep,spell = remainder.partition(' ')    # Charges, Spell
    item = fetchByName(item)
    if item == None:
        actor.hear("That is not here.", color.red)
        return
    if item.uid not in actor.contents:
        actor.hear("You do not have that item.", color.red)
        return
    actor.hear("False alarm... gonna be a while before this is completed.", color.red)
    

def channel_list(actor, target):
    if not target:
        actor.hear("")
        actor.hear("MUD Channels: " + (", ".join(Channel.List)), color.yellow)
        actor.hear("Currently subscribed channels: " + (", ".join(actor.channels)), color.green)
        actor.hear("")
    else:
        if target in actor.channels:
            actor.channels.discard(target)
            actor.hear("Unsubscribed from "+target, color.green)
        else:
            if target in Channel.List:
                actor.channels.add(target)
                actor.hear("Subscribed to "+target, color.green)
            else:
                actor.hear("That channel does not exist.", color.red)
                actor.hear("Ask a wizard to create it.")

def say(actor, msg):
    room = fetch(actor.location)
    if msg != "":
        for uid in room.contents:
            player = fetch(uid)
            if player == None: continue
            if "player" in player.attrs:
                if player != actor: player.hear(actor.name+" says, '"+msg+"'", color.darkgreen)
                else: actor.hear("You say, '"+msg+"'", color.darkgreen)

def tracking(actor, target):
    if target == "":
        actor.hear("Who are you trying to track?", color.red)
        return
    actorRoom = fetch(actor.location)
    target = findPersonInWorld(actor, target)
    if target == None:
        actor.hear("There is no one to track by that name.", color.red)
        return
    if "person" in target.attrs:
        if actor.stats['int'] < 50: actor.miscAttrs['hiding'] = False
        intCheck = random.randint(1, actor.stats['int']+10) # Tracking is fairly difficult...
        if intCheck < actor.stats['int']:
            tracked = False
            actor.hear(color.gray+"Tracking...")
            if (actor.stats['int']*-1)+40 < 5: time.sleep(.5)
            else: time.sleep(((actor.stats['int']*-1)+40)*.1)
            x = 0 # Index placeholder
            for room in target.paths:
                if tracked == True: return
                if room == actor.location:
                    if x == 0:
                        actor.hear(target.name+" is here!!!", color.green)
                        return
                    else:
                        for Exit in actorRoom.exits.keys():
                            if tracked == True: return
                            if actorRoom.exits[Exit] == target.paths[x-1]:
                                if x in range(11, 15):
                                    actor.hear(target.name+color.green+" has not been here recently, but they left to the "+color.reset+Exit+color.green+".")
                                    tracked = True
                                elif x in range(6,10):
                                    actor.hear(target.name+color.green+" left to the "+color.reset+Exit+color.green+" not too long ago!")
                                    tracked = True
                                else: 
                                    actor.hear(target.name+color.green+" left to the "+color.reset+Exit+color.green+" very recently!")
                                    tracked = True
                        if tracked == False:
                            actor.hear(target.name+color.green+" was here, but left no other trails...")
                            return
                x += 1
            if tracked == False:
                actor.hear(target.name+color.green+" was certainly never here.")
                return
        else:
            actor.hear("You can't seem to pick up a trail", color.red)

def trainSkill(actor, target):
    quests.training(actor, target)

def picklock(actor, target):
    """
Syntax:
    pick <direction>

You must first be trained in this skill in order to use it. Once you are trained, you may attempt to
unlock doors to pass through them."""

    room = fetch(actor.location)
    if target == "nose":
        # Emote
        actor.hear("You pick your nose, gross...", color.darkgreen)
        room.broadcast(actor.name+" picks their nose!", color.darkgreen)
        return
    # Sets 'n' to 'north', and likewise for other exits
    if target in DIRECTIONS.keys(): target = DIRECTIONS[target]
    if "lockpicking" not in actor.skills.keys():
        actor.hear("You don't know how to pick locks!", color.red)
        return
    if target is None:
        actor.hear("You must specify what you wish to pick", color.red)
        return
    if target in room.doors.keys():
        if room.doors[target] == 1:
            actor.hear("Noticing the door was not locked, you decided to open just open it.", color.green)
            room.broadcast(actor.name+" bends down to pick the lock, but noticing it was not locked, opened the door.", color.darkgreen, actor)
            return
        check = random.randint(1, actor.skills['lockpicking']+10)
        if check < actor.skills['lockpicking']:
            adjacentRoom = fetch(room.exits[target])
            if adjacentRoom == None:
                actor.hear("There appears to be something wrong with this door. Please contact a Wizard.", color.red)
                return
            otherExit = None
            for direction in adjacentRoom.exits.keys():
                if room.uid == adjacentRoom.exits[direction]:
                    adjacentRoom.doors[direction] -= actor.skills["lockpicking"]
                    otherExit = direction
            room.doors[target] -= actor.skills["lockpicking"]
            if room.doors[target] > 0:
                actor.hear("You make progress on the lock, but it is not yet open", color.green)
                adjacentRoom.broadcast("You hear a click to the "+otherExit+".", color.darkgreen)
            else:
                actor.hear("You pick the lock, and it opens!", color.green)
                room.broadcast(actor.name+" picks the lock, and the door opens!", color.darkgreen, actor)
                adjacentRoom.broadcast("You hear a click to the "+otherExit+" as the door swings open.", color.darkgreen)
        else:
            actor.hear("You are unsuccessful at picking the lock", color.red)
    else:
        actor.hear("Yuauaualgh?", color.red)

def openDoor(actor, target):
    room = fetch(actor.location)
    # Sets 'n' to 'north', and likewise for other exits
    if target in DIRECTIONS.keys(): target = DIRECTIONS[target]
    if target not in room.exits.keys():
        actor.hear("That is not a door. In fact, that is nothing... Please do not open non existan objects!", color.red)
        return
    if target in room.doors.keys():
        if room.doors[target] <= 0:
            actor.hear("That door is already open.", color.red)
            return
        if room.doors[target] > 1: 
            actor.hear("That door is locked!", color.red)
            return
        if room.doors[target] == 1:
            adjacentRoom = fetch(room.exits[target])
            if adjacentRoom == None:
                actor.hear("There appears to be something wrong with this door. Please contact a Wizard.", color.red)
                return
            otherExit = None
            for direction in adjacentRoom.exits.keys():
                if room.uid == adjacentRoom.exits[direction]:
                    adjacentRoom.doors[direction] = 0
                    otherExit = direction
            room.doors[target] = 0
            actor.hear("You open the door to the "+target+".", color.green)
            room.broadcast(actor.name+" opens the door to the "+target+".", color.darkgreen, actor)
            adjacentRoom.broadcast("The door to the "+otherExit+" swings open.", color.darkgreen)
    else: actor.hear("Open.... sesame?", color.red)

def closeDoor(actor, target):
    room = fetch(actor.location)
    # Sets 'n' to 'north', and likewise for other exits
    if target in DIRECTIONS.keys(): target = DIRECTIONS[target]
    if target not in room.exits.keys():
        actor.hear("That is not a door. In fact, that is nothing... Please do not close non existan objects!", color.red)
        return
    if target in room.doors.keys():
        if room.doors[target] >= 1:
            actor.hear("That door is already closed.", color.red)
            return
        if room.doors[target] <= 0:
            adjacentRoom = fetch(room.exits[target])
            if adjacentRoom == None:
                actor.hear("There appears to be something wrong with this door. Please contact a Wizard.", color.red)
                return
            otherExit = None
            for direction in adjacentRoom.exits.keys():
                if room.uid == adjacentRoom.exits[direction]:
                    adjacentRoom.doors[direction] = 1
                    otherExit = direction
            room.doors[target] = 1
            actor.hear("You close the door to the "+target+".", color.green)
            room.broadcast(actor.name+" closes the door to the "+target+".", color.darkgreen, actor)
            adjacentRoom.broadcast("The door to the "+otherExit+" closes.", color.darkgreen)
    else: actor.hear("Close.... sesame?", color.red)

def skillsDisplay(actor, blank):
    actor.hear( "Your skills:", color.green )
    actor.hear( "=" * 30, color.gray )
    for skill in actor.skills.keys():
        if skill == None : continue
        skillName = skill[0].upper() + skill[1:]
        actor.hear ( skillName + ":" + " ".ljust(15-len(skillName)) + str(actor.skills[skill]) )
    actor.hear( "=" * 30, color.gray )
    actor.hear("")

def activateDevice(actor, target):
    room = fetch(actor.location)
    device = findItem(actor, target)
    if device == None: return
    device.activate(actor)

def identify(actor, target):
    item = findInActor(actor, target)
    if item == None:
        actor.hear("You don't have that.", color.red)
        return
    actor.hear(item.name, color.green)
    actor.hear("-"*30)
    for bonus in item.bonus.keys():
        if item.bonus[bonus] != 0:
            actor.hear(bonus+": "+str(item.bonus[bonus]))

def generate(actor, blank):
    ItemDropper.forge(actor)
    actor.hear("A random item has been generated!", color.green)

# Movement methods - Keep new functions above this
def north(player, blank):
    move(player, 'north')
def west(player, blank):
    move(player, 'west')
def south(player, blank):
    move(player, 'south')
def east(player, blank):
    move(player, 'east')
def northeast(player, blank):
    move(player, 'northeast')
def northwest(player, blank):
    move(player, 'northwest')
def southeast(player, blank):
    move(player, 'southeast')
def southwest(player, blank):
    move(player, 'southwest')
def up(player, blank):
    move(player, 'up')
def down(player, blank):
    move(player, 'down')

commands = [
    (["stats", "stat", "score", "sc", "st"], playerStats),
    (["take", "get", "grab", "g"], take),
    (["drop"], drop),
    (["inventory", "stuff", "i", "inv", "bags"], inventory),
    (["wear", "equip"], equip),
    (["eq", "equipment"], showEQ),
    (["remove", "shed", "unequip"], unequip),
    (["go", "move", "walk", "exit", "enter"], move),
    (["look", "examine", "l", "x"], look),
    (["who", "otherplayers"], who),
    (["myuid"], myuid),
    (["save"], save),
    (["time"], worldTime),
    (["attack", "a", "kill", "k"], attack),
    (["health", "hp", "mana"], health),
    (["stop", "break", "br", "bre", "brea"], stop),
    (["cast", "spell", "spells", "magic", "c"], cast),
    (["mail", "post"], mail),
    (["roll", "dice"], rolldice),
    (["help", "info"], info),
    (["meditate", "medi", "med"], meditate),
    (["rest", "r", "res", "re"], rest),
    (["fire", "shoot", "fi", "sh"], rangedAttack),
    (['exp', 'xp'], checkExp),
    (['gain'], gainLevel),
    (['list', 'li'], shopList),
    (['buy', 'purchase', 'bu', 'pur'], purchase),
    (['settings', 'setting', 'set'], settings),
    (['sneak', 'sn', 'sne', 'snea'], sneak),
    (['hide', 'hid', 'hi'], hide),
    (['sea', 'search'], searchRoom),
    (['spot', 'spo', 'sp'], spotPerson),
    (['charge', 'enchant'], enchantItem),
    (['reset'], resetCombatStats),
    (['p', 'party', 'par'], party),
    (["channel", "channellist", "listchannels", "channels"], channel_list),
    (['paths'], myPath),
    (['follow', 'fol', 'foll', 'follo'], followPlayer),
    (['followers'], myFollowers),
    (['say', '.'], say),
    (['track', 'trac', 'tra', 'tr'], tracking),
    (['lockpick', 'picklock', 'pl', 'openlock', 'pick'], picklock),
    (['train'], trainSkill),
    (['open', 'op'], openDoor),
    (['close', 'clos', 'clo'], closeDoor),
    (['skills', 'skill', 'skil', 'ski', 'sk'], skillsDisplay),
    (['pull', 'pul', 'pu', 'use', 'use'], activateDevice),
    (['id', 'identify'], identify),
    (['gen', 'generate'], generate),

    # Movement Commands - keep new commands above this
    (["n", "north"], north),
    (["w", "west"], west),
    (["s", "south"], south),
    (["e", "east"], east),
    (["ne", "northeast"], northeast),
    (["nw", "northwest"], northwest),
    (["se", "southeast"], southeast),
    (["sw", "southwest"], southwest),
    (["u", "up"], up),
    (["d", "down"], down),
]
DIRECTIONS = {'n':'north','s':'south','e':'east','w':'west',
            'nw':'northwest','ne':'northeast','sw':'southwest','se':'southeast'}
